
import {globalCache} from "../utils/globalCache";
import globalGraphics from './globalGraphics';

class Mesh{
    constructor(meshInfo){
        this._meshInfo = meshInfo;
        this._min = meshInfo.min;
        this._max = meshInfo.max;

        // 最终的顶点信息
        this._finalVertexs = [];

        // 为了减少判断,先把数据准备好
        this._localVertex = [];
        this._localNormal = [];
        this._finalNormal = [];
        this._finalColor = []; // 所有顶点的颜色
        let len = Math.floor(meshInfo.vertexs.length / 3);
        let vertexs = meshInfo.vertexs;
        let normals = meshInfo.normals;
        for(let i = 0 ;i < len; ++i){
            let x = vertexs[3 * i];
            let y = vertexs[3 * i + 1];
            let z = vertexs[3 * i + 2];
            this._localVertex[i] = cc.v3(x,y,z);
            this._finalVertexs[i] = cc.v3();
            this._localNormal[i] = cc.v3(normals[3 * i],normals[3 * i + 1],normals[3 * i+2]);
            this._finalNormal[i] = cc.v3();
            this._finalColor[i] = cc.color();
        }
        this._vertexCount = len;
        this._finalIndices = [];

        this._bCullBack = true; // 背面裁剪
        this._bWireFrame = false; // 是否是线框

        // 逆转至
        this._invTranspose = cc.mat4();
    }

    /**
     * 调用此方法后, 所有的顶点都变换到了世界坐标系, 存储在this._finalVertexs[i]里面.
     * 实际用于绘制的 索引 全部存储在 this._finalIndices 中
     * @param camera
     */
    cullFace(camera,worldMat){

        cc.Mat4.inverseTranspose(this._invTranspose,worldMat);

        let invTranspose = this._invTranspose;

        // 在世界坐标系下进行cullFace
        for(let i = 0; i < this._vertexCount; ++i){
            cc.Vec3.transformMat4Normal(this._finalNormal[i],this._localNormal[i],invTranspose);
            cc.Vec3.normalize(this._finalNormal[i],this._finalNormal[i]);

            cc.Vec3.transformMat4(this._finalVertexs[i],this._localVertex[i],worldMat);
        }
        let indices = this._meshInfo.indices;
        if(this._bCullBack){
            // 先做一下背面剔除?
            // 在世界坐标系下做
            let ilen = indices.length / 3;
            this._finalIndices.length = 0;
            let v3_1 = globalCache.get_v3();
            let v3_2 = globalCache.get_v3();
            let camPos = globalCache.get_v3();
            camera.getPos(camPos);

            let v01 = globalCache.get_v3();
            let v12 = globalCache.get_v3();
            for(let i = 0; i < ilen; ++i){

                let v0 = this._finalVertexs[indices[3 * i]];
                let v1 = this._finalVertexs[indices[3 * i + 1]];
                let v2 = this._finalVertexs[indices[3 * i + 2]];

                // 进行背面剔除
                // 求面法线
                // let v01 = cc.v3(v1.x-v0.x,v1.y-v0.y,v1.z-v0.z);
                cc.Vec3.set(v01,v1.x-v0.x,v1.y-v0.y,v1.z-v0.z);

                // let v12 = cc.v3(v2.x-v1.x,v2.y-v1.y,v2.z-v1.z);
                cc.Vec3.set(v12,v2.x-v1.x,v2.y-v1.y,v2.z-v1.z);

                cc.Vec3.cross(v3_1,v01,v12);
                // cc.Vec3.normalize(v3_1,v3_1);  这里只判断符号,可以不用归一化
                cc.Vec3.subtract(v3_2,camPos,v1);
                // cc.Vec3.normalize(v3_2,v3_2);
                if(cc.Vec3.dot(v3_1,v3_2) > 0){
                    // 正面
                    this._finalIndices.push(indices[3 * i],indices[3 * i + 1],indices[3 * i + 2]);
                }
            }

            globalCache.put_v3(v3_1);
            globalCache.put_v3(v3_2);
            globalCache.put_v3(camPos);
            globalCache.put_v3(v01);
            globalCache.put_v3(v12);
        }else{
            // 不进行裁剪
            this._finalIndices.length = indices.length;
            indices.forEach((v,idx)=>{
                this._finalIndices[idx] = v;
            });
        }
    }

    render(camera,material){

        let pvMat = camera.getProjViewMat();
        let color = material.color;

        // let viewMat = camera.getViewMat();
        // let projMat = camera.getProjMat();

        // 在世界坐标系下去计算光照
        let ambientLight = camera.getAmbientLight();
        let diffuseLight = camera.getDiffuseLight();

        let ambColor = ambientLight.finalColor;
        let difColor = diffuseLight.finalColor;
        let lightDir = diffuseLight.dir;

        // 顶点当前处于世界坐标系,继续变换
        for(let i = 0; i < this._vertexCount; ++i){

            let t = Math.max(0,cc.Vec3.dot(this._finalNormal[i],lightDir));

            // 计算光照后的rgb
            let r = ambColor.r + difColor.r * t * color.r / 255;
            let g = ambColor.g + difColor.g * t * color.g / 255;
            let b = ambColor.b + difColor.b * t * color.b / 255;
            cc.Color.set(this._finalColor[i],r,g,b,color.a);

            // 这里一步到位 直接变到了  NDC  下面
            cc.Vec3.transformMat4(this._finalVertexs[i],this._finalVertexs[i],pvMat);

            // 转换成屏幕坐标系
            globalGraphics.viewPort(this._finalVertexs[i]);
        }

        // 绘制出来
        let finalIndices = this._finalIndices;
        let finalLen = finalIndices.length / 3;
        for(let i = 0; i < finalLen; ++i){

            let i0 = finalIndices[3 * i];
            let i1 = finalIndices[3 * i + 1];
            let i2 = finalIndices[3 * i + 2];

            let v0 = this._finalVertexs[i0];
            let v1 = this._finalVertexs[i1];
            let v2 = this._finalVertexs[i2];

            let color0 = this._finalColor[i0];
            let color1 = this._finalColor[i1];
            let color2 = this._finalColor[i2];

            if(this._bWireFrame){
                globalGraphics.gourand3d.drawTriangle(v0,color0,v1,color1,v2,color2);
            }else{
                globalGraphics.gourand3d.fillTriangle(v0,color0,v1,color1,v2,color2);
            }
        }
    }
}
export default Mesh;


